﻿using AutoMapper;
using DTcms.Core.Common.Emum;
using DTcms.Core.Common.Extensions;
using DTcms.Core.Common.Helper;
using DTcms.Core.DBFactory.Database;
using DTcms.Core.IServices;
using DTcms.Core.Model.Models;
using DTcms.Core.Model.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace DTcms.Core.Services
{
    /// <summary>
    /// 会员充值接口实现
    /// </summary>
    public class MemberRechargeService : BaseService, IMemberRechargeService
    {
        private readonly IMemberGroupService _memberGroupService;
        private readonly IUserService _userService;
        private readonly IMapper _mapper;

        public MemberRechargeService(IDbContextFactory contentFactory,
            IMemberGroupService memberGroupService, IUserService userService, IMapper mapper) : base(contentFactory)
        {
            _memberGroupService = memberGroupService;
            _userService = userService;
            _mapper = mapper;
        }

        /// <summary>
        /// 根据条件获取一条记录
        /// </summary>
        public async Task<MemberRechargeDto> QueryAsync(Expression<Func<MemberRechargeDto, bool>> funcWhere,
            WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //联合查询重新组合
            var result = from a in _context.Set<MemberRecharge>()
                         from p in _context.Set<SitePayment>().Where(p => p.Id == a.PaymentId)
                         from u in _context.Set<ApplicationUser>().Where(u => u.Id == a.UserId)
                         select (new MemberRechargeDto
                         {
                             Id = a.Id,
                             UserId = a.UserId,
                             UserName = u.UserName,
                             RechargeNo = a.RechargeNo,
                             PaymentId = a.PaymentId,
                             PaymentTitle = p.Title,
                             Amount = a.Amount,
                             Status = a.Status,
                             AddTime = a.AddTime,
                             CompleteTime = a.CompleteTime
                         });
            //加入查询条件并返回一条
            return await result.FirstOrDefaultAsync(funcWhere);
        }

        /// <summary>
        /// 根据条件获取列表
        /// </summary>
        public async Task<IEnumerable<MemberRechargeDto>> QueryListAsync(int top, Expression<Func<MemberRechargeDto, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //联合查询重新组合
            var result = from a in _context.Set<MemberRecharge>()
                         from p in _context.Set<SitePayment>().Where(p => p.Id == a.PaymentId)
                         from u in _context.Set<ApplicationUser>().Where(u => u.Id == a.UserId)
                         select (new MemberRechargeDto
                         {
                             Id = a.Id,
                             UserId = a.UserId,
                             UserName = u.UserName,
                             RechargeNo = a.RechargeNo,
                             PaymentId = a.PaymentId,
                             PaymentTitle = p.Title,
                             Amount = a.Amount,
                             Status = a.Status,
                             AddTime = a.AddTime,
                             CompleteTime = a.CompleteTime
                         });
            result = result.Where(funcWhere);//加入查询条件
            result = LinqExtensions.OrderByBatch(result, orderBy);//调用Linq扩展类进行排序
            if (top > 0) result = result.Take(top);//等于0显示所有数据
            return await result.ToListAsync();
        }

        /// <summary>
        /// 根据条件获取分页列表
        /// </summary>
        public async Task<PaginationList<MemberRechargeDto>> QueryPageAsync(int pageSize, int pageIndex,
            Expression<Func<MemberRechargeDto, bool>> funcWhere, string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //联合查询重新组合
            var result = from a in _context.Set<MemberRecharge>()
                         from p in _context.Set<SitePayment>().Where(p => p.Id == a.PaymentId)
                         from u in _context.Set<ApplicationUser>().Where(u => u.Id == a.UserId)
                         select (new MemberRechargeDto
                         {
                             Id = a.Id,
                             UserId = a.UserId,
                             UserName = u.UserName,
                             RechargeNo = a.RechargeNo,
                             PaymentId = a.PaymentId,
                             PaymentTitle = p.Title,
                             Amount = a.Amount,
                             Status = a.Status,
                             AddTime = a.AddTime,
                             CompleteTime = a.CompleteTime
                         });
            result = result.Where(funcWhere);//加入查询条件
            result = LinqExtensions.OrderByBatch<MemberRechargeDto>(result, orderBy);//调用Linq扩展类排序
            return await PaginationList<MemberRechargeDto>.CreateAsync(pageIndex, pageSize, result);
        }

        /// <summary>
        /// 新增一条记录
        /// </summary>
        public async Task<MemberRecharge> AddAsync(MemberRechargeEditDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //检查会员是否存在
            var userModel = await _context.Set<Members>().FirstOrDefaultAsync(x => x.UserId == modelDto.UserId);
            if (userModel == null)
            {
                throw new ResponseException("会员账户不存在或已删除", ErrorCode.NotFound);
            }
            //检查支付方式是否存在
            var paymentModel = await _context.Set<SitePayment>().FirstOrDefaultAsync(x => x.Id == modelDto.PaymentId);
            if (paymentModel == null)
            {
                throw new ResponseException("支付方式不存在或已删除", ErrorCode.NotFound);
            }

            //映射到实体
            var model = _mapper.Map<MemberRecharge>(modelDto);
            //创建订单号
            model.RechargeNo= $"RN{UtilConvert.GetGuidToNumber()}";
            model.AddTime = DateTime.Now;
            //保存到数据库
            await _context.Set<MemberRecharge>().AddAsync(model);
            await this.SaveAsync();

            return model;
        }

        /// <summary>
        /// 充值成功后修改状态，添加余额记录，增加会员余额，根据单次充值金额检查升级
        /// </summary>
        /// <param name="rechargeNo">充值单号</param>
        public async Task<bool> CompleteAsync(string rechargeNo, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var model = await _context.Set<MemberRecharge>().FirstOrDefaultAsync(x => x.RechargeNo == rechargeNo);
            if (model == null)
            {
                throw new ResponseException("充值单号有误，请核实", ErrorCode.NotFound);
            }
            //如果已完成确认则直接返回
            if (model.Status == 1)
            {
                return true;
            }
            //查找会员账户
            var userModel = await _context.Set<Members>().FirstOrDefaultAsync(x => x.UserId == model.UserId);
            if (userModel == null)
            {
                throw new ResponseException("会员账户不存在或已删除", ErrorCode.NotFound, StatusCodes.Status404NotFound);
            }
            userModel.Amount += model.Amount;//增加余额
            //查询当前会员组
            var currGroupModel = await _memberGroupService.QueryAsync(x => x.Id == userModel.GroupId);
            if (currGroupModel == null)
            {
                throw new ResponseException("会员组不存在或已删除", ErrorCode.NotFound, StatusCodes.Status404NotFound);
            }
            //检查有无可升级的会员组
            var upgradeGroupModel = await _memberGroupService.QueryAsync(
                x => x.Id != currGroupModel.Id && x.IsUpgrade == 1 && x.Amount <= model.Amount, "-Amount");
            if (upgradeGroupModel != null && upgradeGroupModel.Amount >= currGroupModel.Amount)
            {
                userModel.GroupId = upgradeGroupModel.Id;//升级会员组
            }
            //添加消费记录
            await _context.Set<MemberAmountLog>().AddAsync(new MemberAmountLog()
            {
                UserId = model.UserId,
                Value = model.Amount,
                Remark = $"在线充值，充值单号:{model.RechargeNo}",
                AddTime = DateTime.Now
            });
            //更改订单状态
            model.Status = 1;
            model.CompleteTime = DateTime.Now;
            //更新数据库
            return await this.SaveAsync();
        }

        /// <summary>
        /// 修改支付方式
        /// </summary>
        public async Task<bool> PayAsync(MemberRechargePaymentDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //获取当前登录用户
            var userId = await _userService.GetUserIdAsync();
            //根据ID获取记录
            var model = await _context.Set<MemberRecharge>().Where(x => x.Id == modelDto.Id && x.UserId == userId).FirstOrDefaultAsync();
            //如果不存在则抛出异常
            if (model == null)
            {
                throw new ResponseException("订单不存在或已删除");
            }
            //判断支付方式是否改变
            if (model.PaymentId == modelDto.PaymentId)
            {
                return true;
            }
            //判断是否已支付
            if (model.Status == 1)
            {
                throw new ResponseException("订单已支付，请勿重复");
            }
            //查询支付方式
            model.PaymentId = modelDto.PaymentId;
            //保存到数据库
            _context.Set<MemberRecharge>().Update(model);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 获取充值总数量
        /// </summary>
        public async Task<int> QueryCountAsync(Expression<Func<MemberRecharge, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            return await _context.Set<MemberRecharge>().Where(funcWhere).CountAsync();
        }

        /// <summary>
        /// 获取充值总金额
        /// </summary>
        public async Task<decimal> QueryAmountAsync(Expression<Func<MemberRecharge, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = await _context.Set<MemberRecharge>()
                .Where(funcWhere).OrderByDescending(x => x.AddTime)
                .GroupBy(x => new { x.AddTime.Month, x.AddTime.Day })
                .Select(g => g.Sum(x => x.Amount)).FirstOrDefaultAsync();
            return result;
        }
    }
}
